//    Copyright (C) Kherty.  All rights reserved.
using System;

namespace OpenLS.Spreadsheet
{
    [CLSCompliant(true)]
    public struct Complex
    {
        private readonly double _img;
        private readonly double _real;
        private readonly char _suffix;

        public Complex(double real, double imaginary)
            : this(real, imaginary, 'i')
        {
        }

        public Complex(double real, double imaginary, char suffix)
        {
            _real = real;
            _img = imaginary;
            _suffix = suffix;
        }

        public double Real
        {
            get { return _real; }
        }

        public double X
        {
            get { return Real; }
        }

        public double Y
        {
            get { return Imaginary; }
        }

        public double Imaginary
        {
            get { return _img; }
        }

        public char Suffix
        {
            get { return _suffix; }
        }


        public double Module
        {
            get { return Math.Sqrt(_real*_real + Imaginary*Imaginary); }
        }

        public double Theta
        {
            get { return Math.Atan2(Imaginary, Real); }
        }

        public static bool TryParse(string value, out Complex complex)
        {
            ComplexParser p = new ComplexParser();
            return p.TryParse(value, out complex);
        }
        public static Complex Parse(string value)
        {
            ComplexParser p = new ComplexParser();
            Complex result;
            if (!p.TryParse(value, out result))
                throw new ArgumentException();
            return result;
        }

        public static Complex FromPolar(double mod, double angle, char suffix)
        {
            return new Complex(mod*Math.Cos(angle), mod*Math.Sin(angle), suffix);
        }

        public static Complex operator +(Complex z1, Complex z2)
        {
            return new Complex(z1.X + z2.X, z1.Y + z2.Y, z1.Suffix);
        }

        public static bool operator ==(Complex z1, Complex z2)
        {
            return z1.X == z2.X && z1.Y == z2.Y;
        }

        public static bool operator !=(Complex z1, Complex z2)
        {
            return z1.X != z2.X || z1.Y != z2.Y;
        }

        public static Complex operator -(Complex z1, Complex z2)
        {
            return new Complex(z1.X - z2.X, z1.Y - z2.Y, z1.Suffix);
        }

        public static Complex operator /(Complex z1, Complex z2)
        {
            double a = z1.X;
            double b = z1.Y;
            double c = z2.X;
            double d = z2.Y;
            return new Complex((a*c + b*d)/(c*c + d*d), (b*c - a*d)/(c*c + d*d), z1.Suffix);
        }

        public static Complex operator *(Complex z1, Complex z2)
        {
            return new Complex(z1.X * z2.X - z1.Y * z2.Y, z1.Y * z2.X + z1.X * z2.Y, z1.Suffix);
        }
        public static Complex operator *(Complex z1, double z2)
        {
            return new Complex(z1.X * z2 - z1.Y * 0, z1.Y * z2 + z1.X * 0, z1.Suffix);
        }

        public Complex Conjugate()
        {
            return new Complex(Real, -Imaginary, Suffix);
        }

        public override string ToString()
        {
            if (Imaginary == 0)
                return Real.ToString();
            if (Real == 0)
            {
                if (Imaginary == 1)
                    return Suffix.ToString();
                return Imaginary.ToString() + Suffix;
            }
            if (Imaginary == 1)
                return string.Format("{0}+" + _suffix, Real);
            if (Imaginary == -1)
                return string.Format("{0}-" + _suffix, Real);
            if (Imaginary >= 0)
                return string.Format("{0}+{1}" + _suffix, Real, Imaginary);
            return string.Format("{0}{1}" + _suffix, Real, Imaginary);
        }
        public  string ToString(IFormatProvider provider)
        {
            if (Imaginary == 0)
                return Real.ToString(provider);
            if (Real == 0)
            {
                if (Imaginary == 1)
                    return Suffix.ToString();
                return Imaginary.ToString(provider) + Suffix;
            }
            if (Imaginary == 1)
                return string.Format(provider, "{0}+" + _suffix, Real);
            if (Imaginary == -1)
                return string.Format(provider, "{0}-" + _suffix, Real);
            if (Imaginary >= 0)
                return string.Format(provider, "{0}+{1}" + _suffix, Real, Imaginary);
            return string.Format(provider, "{0}{1}" + _suffix, Real, Imaginary);
        }
        private bool Equals(Complex complex)
        {
            if (_real != complex._real) return false;
            if (_img != complex._img) return false;
            if (_suffix != complex._suffix) return false;
            return true;
        }

        public override bool Equals(object obj)
        {
            if (!(obj is Complex)) return false;
            return Equals((Complex) obj);
        }

        public override int GetHashCode()
        {
            int result = _real.GetHashCode();
            result = 29*result + _img.GetHashCode();
            result = 29*result + _suffix.GetHashCode();
            return result;
        }
    }
}